#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "esp_netif.h"
#include "WifiManager.h"
#include "WifiManager/WiFiManagerDefine.h"
#include "utils/nvsManager.h"

#define TAG "WiFiManager"

struct WifiManager
{
    int retry_count;
    NetConnectType netConnectType;
    wifi_event_callback_t wifi_event_callback;
    tip_callback_t tip_callback;
};

// ---------------- 回调设置 ----------------
void WifiManager_set_event_callback(WifiManager *manager, wifi_event_callback_t cb)
{
    (void)manager;
    manager->wifi_event_callback = cb;
}
void WifiManager_set_tip_callback(WifiManager *manager, tip_callback_t cb)
{
    (void)manager;
    manager->tip_callback = cb;
}

// ---------------- Wi-Fi 事件 ----------------
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
                               int32_t event_id, void *event_data)
{
    WifiManager *manager = (WifiManager *)arg;
    if (!manager)
    {
        ESP_LOGW(TAG, "WifiManager 为空");
        return;
    }

    if (event_base == WIFI_EVENT)
    {
        if (event_id == WIFI_EVENT_STA_DISCONNECTED)
        {
            wifi_event_sta_disconnected_t *disconn = (wifi_event_sta_disconnected_t *)event_data;
            ESP_LOGW(TAG, "STA disconnected, reason: %d", disconn->reason);

            if (manager->retry_count < MAX_RETRY_CONNECT_NET)
            {
                manager->retry_count++;
                ESP_LOGI(TAG, "Retrying Wi-Fi connection... (%d/%d)", manager->retry_count, MAX_RETRY_CONNECT_NET);
                esp_wifi_connect();
            }
            else
            {   
                ESP_LOGI(TAG, "Retrying Wi-Fi connection faild after %d times", MAX_RETRY_CONNECT_NET);
                // 重试5次后，回调再去连上主设备热点后再获取
                if (manager->wifi_event_callback)
                    manager->wifi_event_callback(manager, event_base, event_id, manager->netConnectType);
            }
        }
    }
    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
    {
        ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
        ESP_LOGI(TAG, "Wi-Fi connected, got IP: " IPSTR, IP2STR(&event->ip_info.ip));
        manager->retry_count = 0;

        if (manager->wifi_event_callback)
            manager->wifi_event_callback(manager, event_base, event_id, manager->netConnectType);
    }
}

// ---------------- 初始化 ----------------
WifiManager *wifi_manager_init(wifi_event_callback_t wifi_event_cb, tip_callback_t tip_callback_cb)
{
    WifiManager *manager = calloc(1, sizeof(WifiManager));
    if (!manager)
        return NULL;
    // 设置 Wi-Fi 状态回调
    WifiManager_set_event_callback(manager, wifi_event_cb);
    WifiManager_set_tip_callback(manager, tip_callback_cb);

    ESP_ERROR_CHECK(nvs_flash_init());
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, manager));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, manager));

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_start());
    return manager;
}

// 先连上服务端的热点，等待服务端返回wifi信息后，再配置并连接 WiFi 子设备的wifi每次都必须从主设备获取
void connectWifiOrAp(WifiManager *manager, WiFiConfig *wifiConfig)
{
    if (strlen(wifiConfig->ssid) == 0)
    {
        ESP_LOGI(TAG, "SSID为空,非法传入");
        return;
    }
    manager->netConnectType = wifiConfig->netConnectType;
    // 断开旧连接，配置新 Wi-Fi
    esp_wifi_disconnect();
    manager->retry_count = 0;
    ESP_LOGI(TAG, "StartConnect Wi-Fi, connecting SSID:%s", wifiConfig->ssid);
    wifi_config_t wifi_config = {0};

    strncpy((char *)wifi_config.sta.ssid, wifiConfig->ssid, sizeof(wifi_config.sta.ssid));
    wifi_config.sta.threshold.authmode = WIFI_AUTH_OPEN;
    if (strlen(wifiConfig->password) > 0)
    {
        strncpy((char *)wifi_config.sta.password, wifiConfig->password, sizeof(wifi_config.sta.password));
        wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
    }

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());
    esp_wifi_connect();
}